#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

#include "build_tlv.h"

#define DEBUG 1
#define LOGD(fmt, ...) {if (DEBUG == 1 ) printf("[D][%s:%d] "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__);}


/**********************************************************************************
 *  Function:     void *buid_tlv_head(struct TLV_HEAD *head, char *buffer)
 *  Description:  按网络字节序组建TLV消息的头部 (网络中发送数据时采用此方法)
 *  Input:        struct TLV_MSG *tlvMsg    TLV 消息结构体
 *                char *buffer              TLV 消息存储buffer
 *  Return:       NULL
 **********************************************************************************/
static void *build_tlv_head(struct TLV_MSG *tlvMsg, char *buffer)
{
    if (!tlvMsg || !buffer)
    {
        LOGD("Head or buffer is null, return.")
        return NULL;
    }

    /* TLV 消息头部处理 (进行网络字节序转换) */
    tlvMsg->tlvHead.tlvHeadLength    = htonl(0);        // (int)   TLV 消息的总长度，包括该字段本身。由于第一次构建消息时长度未知，因此先置0，等到消息体构建完毕时再填充
    tlvMsg->tlvHead.tlvHeadVersion   = htons(2);        // (short) TLV 消息的版本号，目前填2
    tlvMsg->tlvHead.tlvHeadCommandId = htons(SEND_MSG); // (short) TLV 消息命令类型
    tlvMsg->tlvHead.tlvHeadSeqence   = htonl(TLV_MSG_SEQENCE);   // (int)   TLV 消息序列号
    memset(tlvMsg->tlvHead.tlvHeadCheckNumber, 0x00, sizeof(tlvMsg->tlvHead.tlvHeadCheckNumber)); // （char） 校验值，保留不使用

    /* 组装TLV 消息头 */
    memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
           &tlvMsg->tlvHead.tlvHeadLength, sizeof(tlvMsg->tlvHead.tlvHeadLength));           // 0~3位存储 tlvHeadLength (注意tlvHeadLength初始值为0)
    tlvMsg->tlvHead.tlvHeadLength += sizeof(tlvMsg->tlvHead.tlvHeadLength);                  // tlvHeadLength(4) = 0 + 4

    memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
           &tlvMsg->tlvHead.tlvHeadVersion, sizeof(tlvMsg->tlvHead.tlvHeadVersion));         // 4~5位存储 tlvHeadVersion
    tlvMsg->tlvHead.tlvHeadLength += sizeof(tlvMsg->tlvHead.tlvHeadVersion);                 // tlvHeadLength(6) = 4 + 2

    memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
           &tlvMsg->tlvHead.tlvHeadCommandId, sizeof(tlvMsg->tlvHead.tlvHeadCommandId));     // 6~7位存储 tlvHeadCommandId
    tlvMsg->tlvHead.tlvHeadLength += sizeof(tlvMsg->tlvHead.tlvHeadCommandId);               // tlvHeadLength(8) = 6 + 2

    memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
           &tlvMsg->tlvHead.tlvHeadSeqence, sizeof(tlvMsg->tlvHead.tlvHeadSeqence));        // 8~11位存储 tlvHeadSeqence
    tlvMsg->tlvHead.tlvHeadLength += sizeof(tlvMsg->tlvHead.tlvHeadSeqence);                // tlvHeadLength(12) = 8 + 4

    memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
           tlvMsg->tlvHead.tlvHeadCheckNumber, sizeof(tlvMsg->tlvHead.tlvHeadCheckNumber)); // 12~27位存储 tlvHeadCheckNumber
    tlvMsg->tlvHead.tlvHeadLength += sizeof(tlvMsg->tlvHead.tlvHeadCheckNumber);            // tlvHeadLength(28) = 12 + 16

    /* TLV 消息序列号处理，若tlvHeadSeqence大于0x7FFFFFFF则初始化置1 */
    if (0x7FFFFFFF > TLV_MSG_SEQENCE)
    {
        TLV_MSG_SEQENCE ++;
    } else {
        TLV_MSG_SEQENCE = 1;
    }

    return NULL;
}

/**********************************************************************************
 *  Function:     void *build_tlv_msg(struct TLV_MSG *tlvMsg,
 *                                           char *buffer, void *value)
 *  Description:  按网络字节序组建TLV消息体
 *  Input:        struct TLV_MSG *tlvMsg    TLV 消息结构体
 *                char *buffer              TLV 消息存储buffer
 *                void *value               需要组建的值
 *  Return:       NULL
 **********************************************************************************/
void *build_tlv_msg(struct TLV_MSG *tlvMsg, char *buffer, void *value)
{
    if (!tlvMsg || !buffer || !value)
    {
        LOGD("Head or buffer or value is null, return.")
        return NULL;
    }

    /* 若TLV_HEAD还没有构建，则先构建TLV_HEAD */
    if (tlvMsg->tlvHead.tlvHeadLength == 0)
    {
        LOGD("tlvHead is NULL, build!");
        build_tlv_head(tlvMsg, buffer);
    }

    /* 根据tlvBodyType对数据进行处理 */
    switch (tlvMsg->tlvBody.tlvBodyType) {
        /* String 型数据处理 */
        case TLV_BODY_TYPE_STRING:
            {
                /* tag */
                short tag    = tlvMsg->tlvBody.tlvBodyTag;
                short tagNbo = htons(tag);

                /* value */
                char *val = (char *)value; // 字符串类型的数据在网络中传输不用转换大小端

                /* value length */
                short valLength    = strlen(val);
                short valLengthNbo = htons(valLength);
                LOGD("(## String ##) Tag: %d, Length: %d, Value: %s", tag, valLength, val);


                memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
                       &tagNbo, sizeof(tagNbo));                        // 28~29位存储 tlvBodyTag (这个时候TLV_HEAD已经构建完成)
                tlvMsg->tlvHead.tlvHeadLength += sizeof(tagNbo);        // tlvHeadLength(30) = 28 + 2

                memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
                       &valLengthNbo, sizeof(valLengthNbo));            // 30~31位存储 tlvBodyValueLength
                tlvMsg->tlvHead.tlvHeadLength += sizeof(valLengthNbo);  // tlvHeadLength(32) = 30 + 2

                memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
                       val, strlen(val));                              // 32~n位存储 tlvBodyValue
                tlvMsg->tlvHead.tlvHeadLength += strlen(val);          // tlvHeadLength(n) = 32 + sizeof(valLengthNbo)

            }
            break;

        /* int 型数据处理 */
        case TLV_BODY_TYPE_INT:
            {
                /* tag */
                short tag    = tlvMsg->tlvBody.tlvBodyTag;
                short tagNbo = htons(tag);

                /* value */
                int val    = *(int *)value;
                int valNbo = htonl(val);

                /* value length */
                short valLength    = sizeof(val);
                short valLengthNbo = htons(valLength);

                LOGD("(##   int  ##) Tag: %d, Length: %d, Value: %d", tag, valLength, val);

                memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
                       &tagNbo, sizeof(tagNbo));                        // 28~29位存储 tlvBodyTag (这个时候TLV_HEAD已经构建完成)
                tlvMsg->tlvHead.tlvHeadLength += sizeof(tagNbo);        // tlvHeadLength(30) = 28 + 2
                memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
                       &valLengthNbo, sizeof(valLengthNbo));            // 30~31位存储 tlvBodyValueLength
                tlvMsg->tlvHead.tlvHeadLength += sizeof(valLengthNbo);  // tlvHeadLength(32) = 30 + 2
                memcpy(buffer + tlvMsg->tlvHead.tlvHeadLength,
                       &valNbo, sizeof(valNbo));                        // 32~35位存储 tlvBodyValue
                tlvMsg->tlvHead.tlvHeadLength += sizeof(valNbo);        // tlvHeadLength(36) = 32 + 4
            }
            break;
        default:
            LOGD("Other tlv body type.")
            break;
    }

    /* 给TLV_HEAD.tlvHeadLength 赋值 */
    int tlvHeadLength = tlvMsg->tlvHead.tlvHeadLength;
    int tlvHeadLengthNbo = htonl(tlvHeadLength);
    memcpy(buffer, &tlvHeadLengthNbo, sizeof(tlvHeadLengthNbo)); // TLV_HEAD.tlvHeadLength占头部前四位，因此buffer的指针不用移动，直接赋值即可

    return NULL;
}